#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>

#include <sys/epoll.h>

#define SERVPORT 3333
#define MAXDATASIZE 100

int main(int argc,char *argv[]) {
    int sockfd, sendbytes;
    char buf[MAXDATASIZE];
    struct hostent* host;
    struct sockaddr_in serv_addr;
	char send_line[MAXDATASIZE], recv_line[MAXDATASIZE];
	int i, n;

    if(argc < 2) {
        fprintf(stderr, "Please enter the server's hostname");
        exit(1);
    }

    if((host = gethostbyname(argv[1])) == NULL) { //转换为hostent
        perror("gethostbyname");
        exit(1);
    }
	
    if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("创建 client socket 失败");
        exit(1);
    }
	
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERVPORT);
    serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
	
    if((connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr))) == -1) {
        perror("connect error");
        exit(1);
    }	
	
	int efd;    
	struct epoll_event event;    
	struct epoll_event *events;
	
	// ① 创建 epoll 实例
	efd = epoll_create(10); 
	if (efd == -1) { 
		perror("epoll create failed"); 
	}
	
	// ② 添加感兴趣的 fd 及其事件到 epoll 实例中
	// 标准输入的可读事件
	event.data.fd = STDIN_FILENO;
    event.events = EPOLLIN;
    if (epoll_ctl(efd, EPOLL_CTL_ADD, STDIN_FILENO, &event) == -1) {
        perror("epoll_ctl add listen fd failed");
    }
	
	// 客户端连接 socket 的可读事件
	event.data.fd = sockfd; 
	event.events = EPOLLIN; 
	if (epoll_ctl(efd, EPOLL_CTL_ADD, sockfd, &event) == -1) { 
		perror("epoll_ctl add listen fd failed"); 
	}

	events = calloc(2, sizeof(event));
	
	for (;;) {
		// ③ 在等待内核 I/O 事件的分发。
		n = epoll_wait(efd, events, 2, -1);
		printf("epoll_wait wakeup\n");
		// 处理 n 个 I/O 事件
		for (i = 0; i < n; i++) {
			// 标准输入有可读事件发生
			if (STDIN_FILENO == events[i].data.fd) {
				if (fgets(send_line, MAXDATASIZE, stdin) != NULL) {
            		if (!strcmp(send_line, "quit\n")) {
                		goto quit;
            		}
					int i = strlen(send_line);
            		if (send_line[i - 1] == '\n') {
                		send_line[i - 1] = 0;
            		}
            		printf("sending '%s'\n", send_line);
            		size_t rt = write(sockfd, send_line, strlen(send_line));
            		if (rt < 0) {
                		perror("write failed");
            		}
            		printf("sended bytes: %zu \n", rt);
        		}
			}
			// 客户端连接 socket 有可读事件发生
			if (sockfd == events[i].data.fd) {
				int n = read(sockfd, recv_line, MAXDATASIZE);
        		if (n < 0) {
            		perror("read failed");
        		} else if (n == 0) {
            		perror("server terminated \n");
        		}
        		recv_line[n] = 0;
        		fputs(recv_line, stdout);
        		fputs("\n", stdout);
			}
		}
	}
quit:
	free(events);
	// 5. 关闭 client socket
    close(sockfd);
}
